package com.acegear.horizon.domain.models;

import com.acegear.horizon.ApplicationContextProvider;
import com.acegear.horizon.domain.events.ClubClaimEvent;
import com.acegear.horizon.domain.events.processers.EventProcessor;
import com.acegear.horizon.domain.models.constraint.ClubMemberType;
import com.acegear.horizon.domain.models.jpa.*;
import com.acegear.horizon.domain.models.vo.ClubMemberVO;
import com.acegear.horizon.domain.models.vo.ClubShareInfoVO;
import com.acegear.horizon.domain.models.vo.ClubVO;
import com.acegear.horizon.domain.models.vo.UserPostVO;
import com.acegear.horizon.domain.repository.jpa.*;
import com.acegear.horizon.domain.services.FollowService;
import org.springframework.data.domain.Pageable;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Created by mercury on 2016/12/18.
 */
public class Club {

	private Integer memberCount;

	private ClubBase base;

	private ClubInfo info;

	private List<ClubMember> members;

	private ClubBaseRepository clubBaseRepository;

	private ClubInfoRepository clubInfoRepository;

	private ClubMemberRepository clubMemberRepository;

	private UserPostRepository userPostRepository;

	private ClubEventBaseRepository clubEventBaseRepository;

	private FollowService followService;

	private EventProcessor eventProcessor;

	private ClubClaimRepository clubClaimRepository;

	public Club() {
		this.members = new ArrayList<>();
	}

	public Club(ClubBase base, ClubInfo info) {
		init();
		this.base = base;
		this.info = info;
		this.members = new ArrayList<>();
		this.memberCount = 0;
	}

	public Club(ClubBase base) {
		init();
		this.base = base;
		this.info = clubInfoRepository.findByClubId(base.getClubId()).get();
		this.memberCount = clubMemberRepository.countByClubId(base.getClubId());
		this.members = new ArrayList<>();
	}

	public ClubBase getBase() {
		return base;
	}

	public ClubInfo getInfo() {
		return info;
	}

	public List<ClubMember> getMembers() {
		return members;
	}

	public void setMembers(List<ClubMember> members) {
		this.members = members;
	}

	public List<ClubMember> getMembers(Long clubId, Pageable pageable) {
		return clubMemberRepository
				.findByClubId(getClubId(), pageable);
	}

	public void init() {
		clubBaseRepository = ApplicationContextProvider.getBean(ClubBaseRepository.class);

		clubInfoRepository = ApplicationContextProvider.getBean(ClubInfoRepository.class);

		clubMemberRepository = ApplicationContextProvider.getBean(ClubMemberRepository.class);

		userPostRepository = ApplicationContextProvider.getBean(UserPostRepository.class);

		clubEventBaseRepository = ApplicationContextProvider.getBean(ClubEventBaseRepository.class);

		followService = ApplicationContextProvider.getBean(FollowService.class);

		eventProcessor = ApplicationContextProvider.getBean("eventProcessor", EventProcessor.class);

		clubClaimRepository = ApplicationContextProvider.getBean(ClubClaimRepository.class);

	}

	public void save() {
		base = clubBaseRepository.save(base);
		info = clubInfoRepository.save(info);
	}

	public void addAndSaveMember(UserInfo userInfo, ClubMemberType rank) {
		if (!isMember(userInfo.getUserId())) {
			members.add(clubMemberRepository.save(new ClubMember(getClubId(), userInfo, rank)));
		}
	}

	public void removeMember(Long userId) {
		clubMemberRepository.deleteByClubIdAndUserId(getClubId(), userId);
	}

	public Long getClubId() {
		return base.getClubId();
	}

	public Optional<ClubMember> getClubOwner() {

		return clubMemberRepository.findByClubIdAndRank(getClubId(), ClubMemberType.FOUNDER).stream().findFirst();
	}

	public List<ClubMember> getClubManagers() {
		return clubMemberRepository.findByClubIdAndRank(getClubId(), ClubMemberType.ADMIN).stream().collect(Collectors.toList());
	}

	public Integer getMemberCount() {
		return memberCount;
	}

	public void update(Club other) {
		ClubBase clubBase = other.getBase();
		base.setClubName(clubBase.getClubName());
		base.setBackground(clubBase.getBackground());
		base.setLogo(clubBase.getLogo());
		base.setRegister(clubBase.getRegister());
		info.getAddress().update(other.getInfo().getAddress());

		info.getContact().update(other.getInfo().getContact());

		info.setIntroduction(other.getInfo().getIntroduction());
		info.setInfo(other.getInfo().getInfo());

		save();
	}

	public void delete() {
		List<ClubMember> clubMembers = clubMemberRepository.findByClubId(base.getClubId());
		clubMemberRepository.delete(clubMembers);
		clubBaseRepository.delete(base);
		clubInfoRepository.delete(info);
	}

	public List<UserPostVO> getClubPosts(Long viewerId, Pageable pageable) {
		return userPostRepository.findByClubIdAndDeletedOrderByIdDesc(getClubId(), false, pageable).stream().map(Post::new)
				.map(post -> post.getUserPostVO(viewerId)).collect(Collectors.toList());
	}

	public Boolean isMember(Long userId) {
		return clubMemberRepository.findByClubIdAndUserId(getClubId(), userId).isPresent();
	}

	public ClubVO getClubVO(Long userId) {
		return new ClubVO(getBase(), getInfo(), isMember(userId));
	}

	public ClubShareInfoVO getShareInfoVO() {
		return new ClubShareInfoVO(getClubId(), base.getClubName(), base.getLogo(), base.getBackground(), getInfo().getInfo(), 0,
				clubEventBaseRepository.countByOwnerId(getClubId()), memberCount);
	}

	public void saveClubClaim(ClubClaim clubClaim) {
		clubClaimRepository.save(clubClaim);
		publishClubClaim(new ClubClaimEvent(clubClaim.getClubId(), clubClaim.getId(), clubClaim.getUserId(), clubClaim.getClubName(),
				clubClaim.getClubInfo(), clubClaim.getPhone(), clubClaim.getLinkman(), clubClaim.getNumber(), clubClaim.getAddress()));
	}

	public ClubClaim queryClubClaim(Long claimId) {
		return clubClaimRepository.findOne(claimId);

	}

	private void publishClubClaim(ClubClaimEvent clubClaimEvent) {
		eventProcessor.publish(clubClaimEvent);
	}
}
